/*
 * @Author: zhaichao 
 * @Date: 2021-03-26 11:51:28 
 * @Last Modified by: zhaichao
 * @Last Modified time: 2021-03-28 13:34:16
 */

import {
    OrbitControls
} from 'three/examples/jsm/controls/OrbitControls';
import {
    Scene,
    PerspectiveCamera,
    WebGLRenderer,
    AxesHelper,
    Mesh,
    TextureLoader,
    AmbientLight,
    BufferGeometry,
    BufferAttribute,
    MeshBasicMaterial,
    DoubleSide,
    PlaneGeometry,
    Vector3,
    Group,
    Euler,
    MathUtils,
    Color,
    Font,
    ShapeGeometry,
    RepeatWrapping,
    Shape,
    BoxGeometry,
    MeshLambertMaterial,
    PointLight,
    CircleGeometry,
    QuadraticBezierCurve3,
    LineCurve3
} from 'three';

import {
    CSS3DRenderer,
    CSS3DObject
} from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import {
    LineMaterial
} from 'three/examples/jsm/lines/LineMaterial.js'
import {
    Line2
} from 'three/examples/jsm/lines/Line2.js'
import {
    LineGeometry
} from 'three/examples/jsm/lines/LineGeometry.js'
import {
    SVGLoader
} from 'three/examples/jsm/loaders/SVGLoader.js';
import {
    TTFLoader
} from 'three/examples/jsm/loaders/TTFLoader.js';

import {
    GLTFLoader
} from 'three/examples/jsm/loaders/GLTFLoader.js';

import dataLists from './data.js'
// import './sea3d'
export default class Crossroads {
    constructor(dom) {
        this.DIS = 120 // 路口距离圆心距离
        this.H = 6000; // 分支的长度
        this.BSEDIS = 30 // 贝塞尔曲线偏移距离
        this.laneWidth = 20; // 每条车道的宽度
        this.rxdWidth = 10 // 行人道长度
        this.rxdHeight = 1 // 行人道宽度
        this.shxWidth = 1 // 双黄线宽度
        this.dataLists = dataLists // 渠化数据

        this.carStatus = 0 // 小车当前状态 0|隐藏 1|起始点到路口阶段 2|路口阶段 3|出车口到终点

        this.CDXW = 500 // 车道线长度
        this.TREEDIS = 30 // 树偏离位置


        // 0绿 1黄 2红
        this.SIGNINFO = {
            default: 0, // 绿灯开始
            height: 50, // 信号灯杆子高度
            0: {
                type: 0,
                time: 60,
                color: 0x00fa00
            },
            1: {
                type: 1,
                time: 4,
                color: 0xfafa00
            },
            2: {
                type: 2,
                time: 80,
                color: 0xfa0000
            },
            3: {
                type: 1,
                time: 4,
                color: 0xfafa00
            }
        }
        this.SIGNH = 50 // 信号灯杆子高度

        this.scene = new Scene();
        this.scene2 = new Scene();
        this.camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
        this.renderer = new WebGLRenderer({
            antialias: true
        });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.setPixelRatio(window.devicePixelRatio);
        dom.appendChild(this.renderer.domElement);
        this.camera.position.set(0, 100, -100);

        this.renderer2 = new CSS3DRenderer();
        this.renderer2.setSize(window.innerWidth, window.innerHeight);
        this.renderer2.domElement.style.position = 'absolute';
        this.renderer2.domElement.style.top = 0;
        this.renderer2.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(this.renderer2.domElement);

        const controls = new OrbitControls(this.camera, this.renderer2.domElement); // 控制器
        controls.maxPolarAngle = Math.PI * 0.5;
        controls.minDistance = 10;
        controls.maxDistance = 500;
        const axesHelper = new AxesHelper(5000); // 辅助线
        axesHelper.renderOrder = 99
        this.scene.add(axesHelper);

        // 光源
        const light = new AmbientLight(0x999999);
        this.scene.add(light);
        const pointLight = new PointLight(0x000000, 1.5);
        pointLight.position.set(100, 100, 90);
        this.scene.add(pointLight);

        // 添加环境
        this.textLoader = new TextureLoader();
        const textcube = this.textLoader.load('/static/sky1.jpg');
        this.scene.background = textcube;

        // 添加草坪
        this.createCp()
        // 创建十字路口
        this.createCross()
        this.render();
    }

    createCp() {
        let textureTest = this.textLoader.load('/static/grasslight-big.jpg');
        textureTest.repeat.set(25, 25);
        textureTest.rotation = Math.PI;
        textureTest.wrapS = RepeatWrapping; // ClampToEdgeWrapping; //RepeatWrapping; //MirroredRepeatWrapping
        textureTest.wrapT = RepeatWrapping; // ClampToEdgeWrapping; //RepeatWrapping; //MirroredRepeatWrapping
        const mesh = new Mesh(new PlaneGeometry(20000, 20000), new MeshBasicMaterial({
            map: textureTest,
            side: DoubleSide
        }));
        mesh.position.y = 0;
        mesh.rotation.x = -Math.PI / 2;
        this.scene.add(mesh);
    }

    // 创建十字路口
    createCross() {
        // 创建路口先创建一个十字路口
        this.dataLists.forEach(item => {
            // 旋转是逆时针旋转的
            const branch = this.setCross(item) // 北
            branch.rotation.y = item.angle * MathUtils.DEG2RAD
            // 获取旋转后四个点的坐标
            item.branchCoord = this.getRotateDeg(item)
            this.scene.add(branch)
        })
        // 根据分支的顶点画出自定义图形
        this.getLanePool()
        // 获取分支顶点坐标画出人行道
        this.getAllBranchDot()
    }

    // 根据分支的顶点画出自定义图形
    getLanePool() {
        let lists = this.dataLists
        // 对数组根据偏转角度进行排序
        lists = lists.sort((a, b) => {
            return a.angle - b.angle
        })
        const shape = new Shape()
        for (let i = 0; i < lists.length; i++) {
            let nearLeftIndex
            if (i + 1 == lists.length) {
                nearLeftIndex = 0
            } else {
                nearLeftIndex = i + 1
            }
            lists[i].nearBranchDataLeft = lists[nearLeftIndex]

            // 加入树模型
            let zd = this.getCenterToYx(lists[i], lists[i].nearBranchDataLeft, -this.TREEDIS)
            let mv = new Vector3(zd.center.x, 0, zd.center.y)
            const loader = new GLTFLoader();
            loader.load('/static/tree.glb', (gltf) => {
                const meshTree = gltf.scene;
                meshTree.position.set(mv.x, 35, mv.z);
                meshTree.scale.set(12, 12, 12)
                meshTree.renderOrder = 10
                this.scene.add(meshTree);
            })

            // 将附近的分支与当前分支顶点组成贝塞尔曲线
            let zb = this.getCenterToYx(lists[i], lists[i].nearBranchDataLeft, this.BSEDIS)
            i == 0 && shape.moveTo(zb.cvl.x, zb.cvl.z)
            shape.lineTo(zb.cvl.x, zb.cvl.z)
            shape.quadraticCurveTo(zb.center.x, zb.center.y, zb.cvr.x, zb.cvr.z)
        }
        let geometry = new ShapeGeometry(shape);
        let mesh = new Mesh(geometry, new MeshBasicMaterial({
            side: DoubleSide,
            color: 0x00000
        }));
        mesh.position.set(0, 0, 0);
        mesh.renderOrder = 2
        mesh.material.depthTest = false;
        mesh.rotation.copy(new Euler(90 * MathUtils.DEG2RAD, 0, 0 * MathUtils.DEG2RAD))
        mesh.matrixAutoUpdate = true
        this.scene.add(mesh)
    }

    // 获取两点之间中心点并将中心点向圆心偏移
    getCenterToYx(cData, lData, bsDis) {
        // cData|当前分支数据 lData|当前相邻左分支分支数据
        const cLb = cData.branchCoord.lb
        const lRb = lData.branchCoord.rb
        const cvl = new Vector3(cLb.x, 0, cLb.y) // 当前分支左下顶点三维坐标
        const cvr = new Vector3(lRb.x, 0, lRb.y) // 相邻左分支顶点三维坐标
        let mv = cvl.clone().add(cvr).divideScalar(2) // 中心坐标
        // 将中心点向圆心偏移达到曲线目的
        let distance = Math.sqrt(mv.x * mv.x + mv.z * mv.z) // 斜角距离
        let angle = Math.atan2(mv.z, mv.x) * 180 / Math.PI // 获取角度
        let x = (distance - bsDis) * Math.cos(angle * Math.PI / 180)
        let y = (distance - bsDis) * Math.sin(angle * Math.PI / 180)

        return {
            cvl,
            cvr,
            center: {
                x,
                y
            }
        }
    }

    // 获取分支交点坐标然后画线
    getAllBranchDot() {
        let lists = this.dataLists
        for (let i = 0; i < lists.length; i++) {
            this.createPavement(lists[i], i)
        }

    }

    // 分支上的模型数据
    createPavement(item, _index) {
        // // 因为需要创建物体坐标系所以点位的经纬度会产生变化以v1为坐标原点,所以坐标
        let vector = new Vector3(item.branchCoord.lb.x, 0, item.branchCoord.lb.y)
        const vector1 = vector.clone().sub(vector) // 左下顶点相对位置
        const vector2 = new Vector3(item.branchCoord.rb.x, 0, item.branchCoord.rb.y).sub(vector)
        const vector3 = new Vector3(item.branchCoord.lb.x, 0, item.branchCoord.lb.y).sub(vector)
        const vector4 = new Vector3(item.branchCoord.lt.x, 0, item.branchCoord.lt.y).sub(vector)
        const angle2 = this.getVector(vector3, vector4) // 分支伸展角度
        const _this = this


        // 创建物体坐标系
        const axesHelper1 = new AxesHelper(200); // 辅助线
        axesHelper1.position.copy(vector)
        // this.scene.add(axesHelper1);

        const allLength = item.lanes.length * this.laneWidth // 总长度
        let num = Math.floor(allLength / (this.rxdHeight + 1))
        let angle3 = 360 - item.angle // 将单个人行道平面中心点平移到右上角

        // 旋转人行道中右上角坐标
        let cood = {
            x: (-this.rxdHeight / 2),
            y: (this.rxdWidth / 2)
        }
        let dCo = this.rotateCoods(cood, angle3) // 旋转后单个矩形的坐标

        const outLanes = item.lanes.filter(item => item.isOut) // 出车道
        let xPaceLine = (vector2.x - vector1.x) / item.lanes.length // 每条车道x距离
        let yPaceLine = (vector2.z - vector1.z) / item.lanes.length // 每条车道y距离

        let coodA = {
            x: (this.rxdHeight / 2),
            y: (this.rxdWidth / 2)
        } // 斑马线左上角坐标
        let dCoG = this.rotateCoods(coodA, angle3) // 旋转后的坐标
        let lfCoodT = new Vector3((dCoG.x1 + dCo.x1), 0, (dCoG.y1 + dCo.y1)) // 矩形左边坐标
        const bmLEndX = _this.rxdWidth * Math.cos(angle2 * MathUtils.DEG2RAD) // 分支加上斑马线x距离(相对距离，是减去左下顶点后的坐标)
        const bmLEndZ = _this.rxdWidth * Math.sin(angle2 * MathUtils.DEG2RAD) // 分支加上斑马线y距离(相对距离，是减去左下顶点后的坐标)
        const bmREndX = _this.rxdWidth * Math.cos(angle2 * MathUtils.DEG2RAD) + item.lanes.length * xPaceLine
        const bmREndz = _this.rxdWidth * Math.sin(angle2 * MathUtils.DEG2RAD) + item.lanes.length * yPaceLine

        let rCoodX = lfCoodT.x + xPaceLine * outLanes.length // 黄线加上斑马线x相对距离
        let rCoodZ = lfCoodT.z + yPaceLine * outLanes.length // 黄线加上斑马线y相对距离
        createBmx() // 创建斑马线
        createBmxFx() // 创建出车道斑马线前的直线
        createCarRoad() // 创建车道边线
        turnSvg() // 转向图标
        createSign() // 创建信号灯


        function createBmx() {
            // 斑马线
            for (let i = 0; i < num; i++) {
                const group = new Group();
                const v3 = vector3.clone().add(vector)
                const sCoodT = new Vector3() // 起点
                let eEndT = new Vector3(bmLEndX, 0, bmLEndZ) // 终点
                let line = _this.createLine(sCoodT, eEndT, '#999')
                group.add(line)
                group.position.copy(v3)
                // 每个矩形按顺序递增
                let xPace = (vector2.x - vector1.x) / num
                let zPace = (vector2.z - vector1.z) / num

                group.translateX(i * xPace)
                group.translateZ(i * zPace)
                _this.scene.add(group)
            }
        }

        function createBmxFx() {
            let rCoodT = new Vector3(rCoodX, 0, rCoodZ) // 直线右边坐标
            const lineT = _this.createLine(lfCoodT.clone().add(vector), rCoodT.clone().add(vector), '#999')
            _this.scene.add(lineT)
        }

        function createCarRoad() {
            item.lanes.forEach((child, index) => {
                if (index + 1 == item.lanes.length) return // 最后一条和中间黄线不画
                let lineT
                let sCoodX = lfCoodT.x + xPaceLine * (index + 1)
                let sCoodZ = lfCoodT.z + yPaceLine * (index + 1)
                let sCoodT = new Vector3(sCoodX, 0, sCoodZ).add(vector) // 这个作为车道起点
                const endX = _this.CDXW * Math.cos(angle2 * MathUtils.DEG2RAD) + sCoodX
                const endY = _this.CDXW * Math.sin(angle2 * MathUtils.DEG2RAD) + sCoodZ
                let eEndT = new Vector3(endX, 0, endY).add(vector) // 这个作为车道终点
                // 注意出车道为实线 进车道为虚线
                if (index + 1 < outLanes.length) {
                    // 出车道
                    lineT = _this.createLine(sCoodT, eEndT, '#999')
                } else if (index + 1 == outLanes.length) {
                    // 双黄线
                    lineT = _this.createLine(sCoodT, eEndT, 'orange')
                } else {
                    // 进车道
                    lineT = _this.createDashedLine(sCoodT, eEndT, '#999')
                }
                _this.scene.add(lineT)
            })
        }

        function createSign() {
            const rCoodT = new Vector3(rCoodX, 0, rCoodZ) // 右边柱子坐标
            const startV = new Vector3(rCoodT.x, _this.SIGNINFO.height / 2, rCoodZ).add(vector) // 左边柱子位置
            const endV = new Vector3(bmREndX + vector.x, _this.SIGNINFO.height / 2, bmREndz + vector.z) // 右边柱子位置
            const centerV = startV.clone().add(endV).divideScalar(2)
            const distance = startV.distanceTo(endV)
            const euler = new Euler(0, (item.angle + 180) * MathUtils.DEG2RAD, 0)
            const SW = 5 // 背景板宽度
            const SH = 12 // 背景板高度
            const signMesh = { // 信号指示灯
                left: '',
                str: '',
                right: ''
            }

            const poleGeo = new BoxGeometry(.5, _this.SIGNINFO.height, .5);
            const poleMat = new MeshLambertMaterial({
                color: 0x999999
            });

            // 左边柱子
            // let mesh1= new Mesh(poleGeo, poleMat);
            // mesh1.position.copy(startV)
            // mesh1.renderOrder = 22
            // mesh1.material.depthTest = false;
            // _this.scene.add(mesh1);

            // 右边柱子
            let mesh2 = new Mesh(poleGeo, poleMat);
            mesh2.position.copy(endV)
            mesh2.renderOrder = 20
            mesh2.material.depthTest = false;
            _this.scene.add(mesh2);

            // 创建杆子
            let mesh3 = new Mesh(new BoxGeometry(distance, .5, .5), poleMat);
            mesh3.position.set(centerV.x, 2 * centerV.y, centerV.z)
            mesh3.renderOrder = 20
            mesh3.rotation.y = item.angle * MathUtils.DEG2RAD
            _this.scene.add(mesh3);

            // 加载小车
            if (_index == 1) loadCarModel()// 加载小车模型（只给第二个车道添加，用于演示）

            // 创建信号灯 红灯颜色#fa0000 绿灯#00fa00
            const loader = new TTFLoader();
            loader.load('/static/Nasa_display.ttf', function (json) {
                const font = new Font(json);
                // 创建背景板
                const plane = _this.createPlane(12, 12, 0x222222, 22, mesh3.position, euler)
                // plane.translateX(-3 * Math.cos(item.angle * MathUtils.DEG2RAD))
                // plane.translateZ(3 * Math.sin(item.angle * MathUtils.DEG2RAD))
                _this.scene.add(plane);

                // 创建背景数字
                const textMaterial = new MeshBasicMaterial({
                    color: 0x555555,
                    opacity: .5
                });
                const shapesT = font.generateShapes(`88`, 8)
                const geometryT = new ShapeGeometry(shapesT);
                geometryT.computeBoundingBox();
                let bgMesh = new Mesh(geometryT, textMaterial);
                bgMesh.renderOrder = 23
                bgMesh.material.depthTest = false;
                bgMesh.position.copy(mesh3.position);
                bgMesh.translateX(5 * Math.cos(item.angle * MathUtils.DEG2RAD))
                bgMesh.translateZ(-5 * Math.sin(item.angle * MathUtils.DEG2RAD))
                bgMesh.rotation.y = (item.angle + 180) * MathUtils.DEG2RAD
                bgMesh.translateY(-4)
                _this.scene.add(bgMesh);

                // 创建里面的计时器
                let type = item.defaultType
                let textMesh // 模型网格
                let time = _this.SIGNINFO[type].time // 时间
                let color = _this.SIGNINFO[type].color // 颜色
                crFun()
                setSignalIcon(1)
                setInterval(() => {
                    time = time - 1
                    color = _this.SIGNINFO[type].color
                    crFun()
                    if (time == 0) {
                        type = (type < 3 && (type + 1)) || 0
                        time = _this.SIGNINFO[type].time
                        setSignalIcon(2)
                    }
                }, 1000)

                // 创建指示灯svg网格
                function setSignalIcon(cjType) {
                    // type 0|绿灯 1|黄灯 2|红灯 3|黄灯
                    // cjType 1|立即执行 2|延迟一秒执行
                    if (cjType == 1) {
                        setTimeout(() => {
                            c()
                        }, 1000);
                    } else {
                        c()
                    }


                    function c() {
                        if (type == 0) {
                            clearSign()
                            // 左转绿灯
                            _this.createSvg('static/leftGreen.svg', 0.004, euler, leftV, 23).then(group => {
                                signMesh.left = group.clone()
                                signMesh.left.translateX(-SW / 2 + 0.4)
                                signMesh.left.translateY(-SH / 2)
                                _this.scene.add(signMesh.left);
                            })
                            // 直行绿灯
                            signMesh.str = _this.crateCircle(1, 0x00fa00, cV, euler, 23)
                            signMesh.str.translateY(-4)
                            _this.scene.add(signMesh.str);
                            // 右转绿灯
                            _this.createSvg('static/rightGreen.svg', 0.004, euler, rightV, 23).then(group => {
                                signMesh.right = group.clone()
                                signMesh.right.translateX(-SW / 2 + 0.4)
                                signMesh.right.translateY(-SH / 2)
                                _this.scene.add(signMesh.right);
                            })
                        } else if (type == 2) {
                            clearSign()
                            //左转红灯
                            _this.createSvg('static/leftRed.svg', 0.004, euler, leftV, 23).then(group => {
                                signMesh.left = group.clone()
                                signMesh.left.translateX(-SW / 2 + 0.4)
                                signMesh.left.translateY(-SH / 2 + 3.8 * 2)
                                _this.scene.add(signMesh.left);
                            })
                            //直行红灯
                            signMesh.str = _this.crateCircle(1, 0xfa0000, cV, euler, 23)
                            signMesh.str.translateY(4)
                            _this.scene.add(signMesh.str);
                            //右转绿灯
                            _this.createSvg('static/rightGreen.svg', 0.004, euler, rightV, 23).then(group => {
                                signMesh.right = group.clone()
                                signMesh.right.translateX(-SW / 2 + 0.4)
                                signMesh.right.translateY(-SH / 2 + 3.8 * 2)
                                _this.scene.add(signMesh.right);
                            })
                        } else {
                            // 直行黄灯
                            _this.scene.remove(signMesh.str)
                            signMesh.str = _this.crateCircle(1, 0xfafa00, cV, euler, 23)
                            _this.scene.add(signMesh.str);
                        }
                    }
                }

                function clearSign() {
                    signMesh.left && _this.scene.remove(signMesh.left)
                    signMesh.str && _this.scene.remove(signMesh.str)
                    signMesh.right && _this.scene.remove(signMesh.right)
                }


                // 创建数字网格
                function crFun() {
                    const textMaterial = new MeshBasicMaterial({
                        color
                    });
                    const shapes = font.generateShapes(`${time < 10 ? '0' + time : time}`, 8)
                    const geometry = new ShapeGeometry(shapes);
                    geometry.computeBoundingBox();

                    if (textMesh) {
                        textMesh.geometry.dispose()
                        _this.scene.remove(textMesh)
                    }
                    textMesh = new Mesh(geometry, textMaterial);
                    textMesh.renderOrder = 23
                    textMesh.material.depthTest = false;
                    textMesh.position.copy(mesh3.position);

                    textMesh.translateX(5 * Math.cos(item.angle * MathUtils.DEG2RAD))
                    textMesh.translateZ(-5 * Math.sin(item.angle * MathUtils.DEG2RAD))
                    textMesh.rotation.y = (item.angle + 180) * MathUtils.DEG2RAD
                    textMesh.translateY(-4)

                    _this.scene.add(textMesh);
                }
            });
            // 左转
            const leftV = new Vector3(rCoodX, _this.SIGNINFO.height, rCoodZ).add(vector)
            signBasicMethod('static/leftGray.svg', leftV)
            // 直行图标引不进来自己画一个
            const cV = new Vector3((centerV.x + leftV.x) / 2, _this.SIGNINFO.height, (centerV.z + leftV.z) / 2)
            signStrMethod(cV)
            // 右转
            const rightV = new Vector3((endV.x + centerV.x) / 2, _this.SIGNINFO.height, (endV.z + centerV.z) / 2)
            signBasicMethod('static/rightGray.svg', rightV)

            // 创建直行
            function signStrMethod(pos) {
                const SW = 5 // 背景板宽度
                const SH = 12 // 背景板高度
                const euler = new Euler(0, (item.angle + 180) * MathUtils.DEG2RAD, 0)
                const plane = _this.createPlane(SW, SH, 0x222222, 22, pos, euler)
                _this.scene.add(plane)

                for (let i = 0; i < 3; i++) {
                    const circle = _this.crateCircle(1, 0x555555, pos, euler, 22)
                    circle.translateY((i - 1) * 4)
                    _this.scene.add(circle)
                }


            }

            // 创建基础信号指示器
            function signBasicMethod(url, pos) {
                // 背景板
                const euler = new Euler(0, (item.angle + 180) * MathUtils.DEG2RAD, 0)
                const plane = _this.createPlane(SW, SH, 0x222222, 22, pos, euler)
                _this.scene.add(plane)

                // 背景灯
                for (let i = 0; i < 3; i++) {
                    _this.createSvg(url, 0.004, euler, pos, 22).then(group => {
                        group.translateX(-SW / 2 + 0.4)
                        group.translateY(-SH / 2 + 3.8 * i)
                        _this.scene.add(group);
                    })
                }
            }
        }

        // 创建图标
        function turnSvg() {
            const loader = new SVGLoader();
            item.lanes.forEach((child, index) => {
                let url
                url = (child.isOut && `static/svg/${child.fxfx}.svg`) || `static/svg/1.svg`
                loader.load(url, function (data) {
                    const paths = data.paths;
                    const group = new Group();
                    let space = 0 // 偏移距离
                    group.scale.multiplyScalar(0.01);
                    if (child.isOut) {
                        space = 20
                        group.rotation.copy(new Euler(-90 * MathUtils.DEG2RAD, 0, (item.angle + 180) * MathUtils.DEG2RAD))
                    } else {
                        space = 10
                        group.rotation.copy(new Euler(-90 * MathUtils.DEG2RAD, 0, item.angle * MathUtils.DEG2RAD))
                    }


                    // 根据车道来定所在位置
                    let startX = lfCoodT.x + xPaceLine * index
                    let startZ = lfCoodT.z + yPaceLine * index
                    const endX = lfCoodT.x + xPaceLine * (index + 1) // 下一个车道的x起点
                    const endZ = lfCoodT.z + yPaceLine * (index + 1) // 下一个车道的z起点
                    const moX = space * Math.cos(angle2 * MathUtils.DEG2RAD) + (startX + endX) / 2 + vector.x
                    const moZ = space * Math.sin(angle2 * MathUtils.DEG2RAD) + (startZ + endZ) / 2 + vector.z

                    group.position.set(moX, 0, moZ)

                    // 图标本身有偏移
                    group.translateX(-5)
                    group.translateY(-10.5)


                    for (let i = 0; i < paths.length; i++) {
                        const path = paths[i];
                        const fillColor = path.userData.style.fill;
                        if (fillColor !== undefined && fillColor !== 'none') {
                            const material = new MeshBasicMaterial({
                                color: new Color().setStyle(fillColor),
                                opacity: path.userData.style.fillOpacity,
                                side: DoubleSide,
                                depthWrite: false,
                                wireframe: 14
                            });

                            const shapes = path.toShapes(true);

                            for (let j = 0; j < shapes.length; j++) {

                                const shape = shapes[j];

                                const geometry = new ShapeGeometry(shape);
                                const mesh = new Mesh(geometry, material);
                                mesh.name = `${item.angle}-${index}`;

                                mesh.renderOrder = 9
                                mesh.material.depthTest = false;

                                group.add(mesh);

                            }

                        }
                    }
                    _this.scene.add(group)
                })
            })
        }

        // 小车模型加载
        function loadCarModel() {
            for (let i = 0; i < 2; i++) {
                const gltfLoader = new GLTFLoader();
                let startX = lfCoodT.x + xPaceLine * i
                let startZ = lfCoodT.z + yPaceLine * i
                const endX = lfCoodT.x + xPaceLine * (i + 1) // 下一个车道的x起点
                const endZ = lfCoodT.z + yPaceLine * (i + 1) // 下一个车道的z起点
                const moX = _this.CDXW * Math.cos(angle2 * MathUtils.DEG2RAD) + (startX + endX) / 2 + vector.x
                const moZ = _this.CDXW * Math.sin(angle2 * MathUtils.DEG2RAD) + (startZ + endZ) / 2 + vector.z

                const carEMX = 20 * Math.cos(angle2 * MathUtils.DEG2RAD) + (startX + endX) / 2 + vector.x // 人行道小车停下的x
                const carEMZ = 20 * Math.sin(angle2 * MathUtils.DEG2RAD) + (startZ + endZ) / 2 + vector.z // 人行道小车停下的Z

                gltfLoader.load(`/static/car${i + 1}.glb`, (gltf) => {
                    const mesh = gltf.scene;
                    mesh.name = `gltf-car-${i + 1}`
                    mesh.scale.set(700, 800, 800)
                    mesh.position.set(moX, 2, moZ);
                    mesh.rotateY((item.angle + 180) * MathUtils.DEG2RAD) // 模型本身偏转180°
                    mesh.renderOrder = 10
                    mesh.castShadow = true
                    _this.scene.add(mesh);

                    mesh.userData.currentIndex = 0 // 当前路径索引
                    mesh.userData.leftAngle = item.nearBranchDataLeft.angle // 即将偏转的角度
                    mesh.userData.curAngle = item.angle // 当前偏转的角度


                    // 第一阶段
                    const p1 = new Vector3(moX, 2, moZ) // 起点
                    const p2 = new Vector3(carEMX, 2, carEMZ) // 终点
                    mesh.userData.points1 = _this.getLinePoints(p1, p2) // 第一阶段

                    // 第二阶段
                    let p3, p4 // p3为下一个位置终点
                    if (i == 0) {
                        // 右转
                        const nearBranchDataLeft = item.nearBranchDataLeft
                        // p3 = new Vector3(item.branchCoord.lb.x, 0, item.branchCoord.lb.y)
                        // p4 = new Vector3(nearBranchDataLeft.branchCoord.rb.x, 0, nearBranchDataLeft.branchCoord.rb.y)
                        const lc = _this.scene.getObjectByName(`${nearBranchDataLeft.angle}-${item.lanes.length - 1}`).parent.position.clone()
                        // 图标位置调整过获取中心点需要调回来
                        p3 = new Vector3(lc.x - 5, 0, lc.z)
                        const c1 = p2.clone().add(p3).divideScalar(3) // 第一个途径点
                        const c2 = p2.clone().add(p3).divideScalar(3).multiplyScalar(2) // 第二个途径点
                        mesh.userData.points2 = _this.getCubicPoints(p2, c1, c2, p3) // 第二阶段
                    } else {
                        // 直行
                    }

                    // const p2 = 
                    // const p3 = p1.clone().add(p4).divideScalar(3).multiplyScalar(2) // 途径点2

                })
            }
        }
    }


    // 取直线的途径点
    getLinePoints(v1, v2) {
        const line = new LineCurve3(v1, v2)
        return line.getPoints(150)
    }

    // 获取贝塞尔曲线途径点
    getCubicPoints(p1, v, v2, p4) {
        let distance = Math.sqrt(v.x * v.x + v.z * v.z) // 斜角距离
        let angle = Math.atan2(v.z, v.x) * 180 / Math.PI  // 获取角度
        let x = (distance - this.BSEDIS) * Math.cos(angle * Math.PI / 180)
        let z = (distance - this.BSEDIS) * Math.sin(angle * Math.PI / 180)
        // const c1 = new Vector3(p1.x - 10, 0, p1.z - 8)
        const c2 = new Vector3(x, 0, z)
        // let curve = new CubicBezierCurve3(p1, c1, c2, p4)
        let curve = new QuadraticBezierCurve3(p1, c2, p4)
        return curve.getPoints(150)
    }


    // 旋转算法
    rotateCoods(a, angle) {
        const {
            x,
            y
        } = {
            ...a
        }
        var x1 = Math.cos(angle * MathUtils.DEG2RAD) * x - Math.sin(angle * MathUtils.DEG2RAD) * y
        var y1 = Math.cos(angle * MathUtils.DEG2RAD) * y + Math.sin(angle * MathUtils.DEG2RAD) * x
        return {
            x1,
            y1
        }
    }


    // 更新小车位置
    updateCarPossition() {
        let car1 = this.scene.getObjectByName('gltf-car-1') // 小蓝车
        let car2 = this.scene.getObjectByName('gltf-car-2') // 小红车
        if (car1) {
            // 读取当前状态根据状态来区分小车该运动第几个阶段
            if ((this.carStatus == 0) && (car1.userData.currentIndex < car1.userData.points1.length)) {
                car1.position.copy(car1.userData.points1[car1.userData.currentIndex])
                car1.userData.currentIndex += 1
                if (car1.userData.currentIndex == car1.userData.points1.length) {
                    car1.userData.currentIndex = 0
                    this.carStatus = 1
                }
            }

            // 第二阶段
            if (this.carStatus == 1 && car1.userData.currentIndex < car1.userData.points2.length) {
                car1.position.copy(car1.userData.points2[car1.userData.currentIndex])
                car1.userData.currentIndex += 1
                // 注意需要旋转
                const angleDis = Math.abs(car1.userData.leftAngle - car1.userData.curAngle)  // 需要偏转的角度
                console.log(angleDis)
                car1.rotateY((car1.rotation.y * MathUtils.DEG2RAD - angleDis / car1.userData.points2.length) * MathUtils.DEG2RAD )
                if (car1.userData.currentIndex == car1.userData.points2.length) {
                    car1.userData.currentIndex = 0
                    this.carStatus = 2
                }
            }


        }
        if (car2) {
            // 读取当前状态根据状态来区分小车该运动第几个阶段
            if (car2.userData.currentIndex < car2.userData.points1.length) {
                car2.position.copy(car2.userData.points1[car2.userData.currentIndex])
                car2.userData.currentIndex += 1
            }
        }
    }



    // 根据两点坐标获取偏转角度
    getVector(a, b) {
        const y = b.z - a.z
        const x = b.x - a.x
        let angle = Math.atan2(y, x) * 180 / Math.PI
        return angle
    }


    // 创建svg
    createSvg(url, scale, euler, position, order) {
        return new Promise((reslove, reject) => {
            const loader = new SVGLoader();
            const group = new Group();
            loader.load(url, function (data) {
                const paths = data.paths;
                group.scale.multiplyScalar(scale);
                group.position.copy(position)
                group.rotation.copy(euler)
                group.translateX
                for (let i = 0; i < paths.length; i++) {
                    const path = paths[i];
                    const fillColor = path.userData.style.fill;
                    if (fillColor !== undefined && fillColor !== 'none') {
                        const material = new MeshBasicMaterial({
                            color: new Color().setStyle(fillColor),
                            opacity: path.userData.style.fillOpacity,
                            // side: DoubleSide,
                            depthWrite: false,
                            wireframe: 14
                        });
                        const shapes = path.toShapes(true);

                        for (let j = 0; j < shapes.length; j++) {

                            const shape = shapes[j];

                            const geometry = new ShapeGeometry(shape);
                            const mesh = new Mesh(geometry, material);
                            group.add(mesh);
                        }

                    }
                }
                group.renderOrder = order
                reslove(group)
            })
        })
    }


    // 创建几何图形
    createPlane(width, height, color, order, pos, rot) {
        const geometry = new PlaneGeometry(width, height);
        const material = new MeshBasicMaterial({
            color,
            side: DoubleSide
        });
        const plane = new Mesh(geometry, material);
        plane.renderOrder = order
        plane.material.depthTest = false;
        plane.position.copy(pos);
        plane.rotation.copy(rot)
        return plane
    }

    // 创建圆
    crateCircle(radius, color, pos, rot, renderOrder) {
        const geometry = new CircleGeometry(radius, 50);
        const material = new MeshBasicMaterial({ color });
        const circle = new Mesh(geometry, material);
        circle.renderOrder = renderOrder
        circle.material.depthTest = false;
        circle.position.copy(pos)
        circle.rotation.copy(rot)
        return circle
        // circle.translateY((i - 1) * 4)
        // _this.scene.add(circle)
    }

    // 创建直线
    createLine(start, end, color) {
        const points = [];
        points.push(start.x, start.y, start.z);
        points.push(end.x, end.y, end.z);
        const geometry = new LineGeometry()
        geometry.setPositions(points)
        const material = new LineMaterial({
            color,
            linewidth: 2,
            opacity: .7
        });
        material.resolution.set(window.innerWidth, window.innerHeight);
        material.depthTest = false
        const line = new Line2(geometry, material);
        line.renderOrder = 9
        line.computeLineDistances();
        return line
    }

    // 创建虚线
    createDashedLine(start, end, color) {
        const points = [];
        points.push(start.x, start.y, start.z);
        points.push(end.x, end.y, end.z);
        const geometry = new LineGeometry()
        geometry.setPositions(points)
        const material = new LineMaterial({
            color,
            linewidth: 2,
            dashSize: 10,
            gapSize: 2,
            opacity: .7
        });
        material.defines.USE_DASH = ""
        // const lineDashedMaterial = new LineDashedMaterial( { vertexColors: true, scale: 2, dashSize: 1, gapSize: 1 } );
        material.resolution.set(window.innerWidth, window.innerHeight);
        material.depthTest = false
        const line = new Line2(geometry, material);
        line.renderOrder = 9
        line.computeLineDistances();
        return line
    }

    // 获取四个角度旋转后的坐标
    getRotateDeg(item) {
        const angle = item.angle // 旋转角度
        let obj = {}; // 定义左上，右上,左下,右下坐标
        obj.lt = this.getCoords(angle, {
            x: item.xIn,
            y: this.H + this.DIS
        }, item.obliqueLeftTop)
        obj.lb = this.getCoords(angle, {
            x: item.xIn,
            y: this.DIS
        }, item.obliqueLeftBot)

        obj.rt = this.getCoords(angle, {
            x: -item.xOut,
            y: this.H + this.DIS
        }, item.obliqueRightTop)
        obj.rb = this.getCoords(angle, {
            x: -item.xOut,
            y: this.DIS
        }, item.obliqueRightBot)
        return obj
    }

    // 根据坐标和角度获取旋转后的坐标
    getCoords(angle, coord, oblique) {
        let x, y
        let ange = Math.atan2(coord.y, coord.x) * 180 / Math.PI // 本身偏移量

        angle = ange - angle // 最后偏移的角度
        if (coord.y == this.DIS) {
            // 如果y值为0则旋转时候不根据this.Z算半径
            x = oblique * Math.cos(angle * Math.PI / 180)
            y = oblique * Math.sin(angle * Math.PI / 180)
        } else {
            x = oblique * Math.cos(angle * Math.PI / 180)
            y = oblique * Math.sin(angle * Math.PI / 180)
        }
        return {
            x,
            y
        }
    }

    // 创建分支
    setCross(item) {
        const Y = this.H
        const DIS = this.DIS
        const TZ = this.H + this.DIS
        const BZ = this.DIS

        // 计算分支宽度
        const outLanes = item.lanes.filter(item => item.isOut) // 出车道
        const inLanes = item.lanes.filter(item => !item.isOut) // 近车道
        item.xIn = inLanes.length * this.laneWidth // 入的宽度
        item.xOut = outLanes.length * this.laneWidth // 出的宽度
        item.obliqueLeftTop = Math.sqrt(item.xIn * item.xIn + TZ * TZ) // 入车道原点到左上的距离
        item.obliqueRightTop = Math.sqrt(item.xOut * item.xOut + TZ * TZ) // 入车道原点到右上的距离
        item.obliqueLeftBot = Math.sqrt(item.xIn * item.xIn + BZ * BZ) // 入车道原点到左下的距离
        item.obliqueRightBot = Math.sqrt(item.xOut * item.xOut + BZ * BZ) // 入车道原点到右下的距离

        const geometry = new BufferGeometry();
        geometry.needsUpdate = true;
        const vertices = new Float32Array([
            item.xIn, 0, DIS,
            -item.xOut, 0, DIS,
            -item.xOut, 0, Y,
            -item.xOut, 0, Y,
            item.xIn, 0, Y,
            item.xIn, 0, DIS
        ]);
        geometry.setAttribute('position', new BufferAttribute(vertices, 3));
        const material = new MeshBasicMaterial({
            color: 0x00000,
            side: DoubleSide
        });
        const mesh = new Mesh(geometry, material);
        mesh.renderOrder = 2
        mesh.material.depthTest = false;
        return mesh;
    }

    render() {
        // 更新小车位置
        this.updateCarPossition()


        window.requestAnimationFrame(() => this.render());
        this.camera.updateProjectionMatrix();
        this.renderer2.render(this.scene2, this.camera);
        this.renderer.render(this.scene, this.camera);
    }
}